using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using ShootThemUp.Sources.PlayerInputs;
using ShootThemUp.Sources.ScreenManagement;
using Microsoft.Xna.Framework.Content;
using ShootThemUp.Sources.GameElements.Weapons;

namespace ShootThemUp.Sources.GameElements.Ships.Player
{

    /// <summary>
    /// This class represents the ship controled by the player
    /// and determines his movements.
    /// </summary>
    public class PlayerShip : Ship
    {

        #region Spritesheet Constants Fields
       
        /// <summary>
        /// The X position of the player ship hitbox (in px).
        /// </summary>
        private const int HITBOX_POSITION_X = 10;
        /// <summary>
        /// The Y position of the player ship hitbox (in px).
        /// </summary>
        private const int HITBOX_POSITION_Y = 12;
        /// <summary>
        /// The width of the player ship hitbox (in px).
        /// </summary>
        private const int HITBOX_WIDTH = 16;
        /// <summary>
        /// The height of the player ship hitbox (in px).
        /// </summary>
        private const int HITBOX_HEIGHT = 11;
        /// <summary>
        /// The X position of the player ship texture in the spritesheet (in px).
        /// </summary>
        private const int SPRITESHEET_POSITION_X = 0;
        /// <summary>
        /// The Y position of the player ship texture in the spritesheet (in px).
        /// </summary>
        private const int SPRITESHEET_POSITION_Y = 0;
        /// <summary>
        /// The width of the player ship texture in the spritesheet (in px).
        /// </summary>
        private const int SPRITESHEET_WIDTH = 42;
        /// <summary>
        /// The height of the player ship texture in the spritesheet (in px).
        /// </summary>
        private const int SPRITESHEET_HEIGHT = 35;
        /// <summary>
        /// The number of sprites used to animate the ship.
        /// </summary>
        private const int NUMBER_OF_FRAME = 4;
        /// <summary>
        /// The duration of a frame of the animation.
        /// </summary>
        private const float ANIMATION_DURATION = 0.01f;

        #endregion

        #region Display Constants Fields

        /// <summary>
        /// The distance between the bottom of the screen and the initial X position of the ship (in px).
        /// </summary>
        private const int INIT_Y_MARGIN = 50;

        #endregion

        #region Model Constant Fields

        /// <summary>
        /// The default life of the player ship.
        /// </summary>
        public const int DEFAULT_LIFE = 1000;
        /// <summary>
        /// The default number of simple shot of the player ship.
        /// </summary>
        public const int DEFAULT_SIMPLE_SHOT_NUMBER = 3;
        /// <summary>
        /// The default number of ball shot of the player ship.
        /// </summary>
        public const int DEFAULT_BALL_SHOT_NUMBER = 5;
        /// <summary>
        /// The default time between two shot of the player ship.
        /// </summary>
        public const int DEFAULT_RELOAD_TIME = 200;
        /// <summary>
        /// The default weapon of the player ship.
        /// </summary>
        public const WeaponType DEFAULT_WEAPON = WeaponType.MultiBallShot;

        #endregion

        #region Fields

        /// <summary>
        /// The current player score.
        /// </summary>
        private int score;
        /// <summary>
        /// The index of the current animation.
        /// </summary>
        private float index;
        /// <summary>
        /// Direction of the animation, 1 or -1.
        /// </summary>
        private int animationDirection = 1;
        /// <summary>
        /// The player life bar, displayed on the screen.
        /// </summary>
        private LifeBar lifeBar;
        /// <summary>
        /// The player reactors.
        /// </summary>
        private Reactor reactor;

        #endregion

        #region Properties

       
        /// <summary>
        /// Gets or sets the player score.
        /// </summary>
        /// <value>
        /// The current player score.
        /// </value>
        public int Score
        {
            get { return score; }
            set { score = value; }
        }

        #endregion

        #region Initialization

        /// <summary>
        /// Initializes a new instance of the <see cref="PlayerShip"/> class.
        /// </summary>
        public PlayerShip(int life, Weapon weapon) 
            : base(life, 
            weapon,
            new Vector2(GameStateManagement.DEFAULT_PORTRAIT_SCREEN_WIDTH / 2 - PlayerShip.SPRITESHEET_WIDTH / 2,GameStateManagement.DEFAULT_PORTRAIT_SCREEN_HEIGHT - PlayerShip.SPRITESHEET_HEIGHT - PlayerShip.INIT_Y_MARGIN),
            Vector2.Zero,
            new Rectangle(PlayerShip.SPRITESHEET_POSITION_X, PlayerShip.SPRITESHEET_POSITION_Y, PlayerShip.SPRITESHEET_WIDTH, PlayerShip.SPRITESHEET_HEIGHT),
            new Rectangle(PlayerShip.HITBOX_POSITION_X, PlayerShip.HITBOX_POSITION_Y, PlayerShip.HITBOX_WIDTH, PlayerShip.HITBOX_HEIGHT))
        {           
            this.lifeBar = new LifeBar();
            this.reactor = new Reactor(this.Position);
        }

        /// <summary>
        /// Loads the Texture2D in the game.
        /// </summary>
        /// <param name="content">The content manager.</param>
        /// <param name="assetName">Name of the asset to load, ie the name.</param>
        public override void LoadContent(ContentManager content, string assetName)
        {
            this.lifeBar.LoadContent(content, assetName);
            this.reactor.LoadContent(content, assetName);
            base.LoadContent(content, assetName);
        }

        #endregion

        #region Update & Draw

        /// <summary>
        /// Updates the sprite position and the sprite animation in function of the specified game time.
        /// </summary>
        /// <param name="gameTime">A snapshot of the current time.</param>
        public override void Update(GameTime gameTime)
        {

            #region Animation of the Texture

            this.index += this.animationDirection * gameTime.ElapsedGameTime.Milliseconds * PlayerShip.ANIMATION_DURATION;

            if (index >= PlayerShip.NUMBER_OF_FRAME)
                this.animationDirection = -1;
            else if (index < 0)
                this.animationDirection = 1;
            else
                this.SourceRectangle = new Rectangle(PlayerShip.SPRITESHEET_POSITION_X + (int)index * PlayerShip.SPRITESHEET_WIDTH, PlayerShip.SPRITESHEET_POSITION_Y, PlayerShip.SPRITESHEET_WIDTH, PlayerShip.SPRITESHEET_HEIGHT);

            #endregion

            #region Ship Movement

            int nextX = (int)(this.Position.X + this.Speed.X * gameTime.ElapsedGameTime.Milliseconds);
            int nextY = (int)(this.Position.Y + this.Speed.Y * gameTime.ElapsedGameTime.Milliseconds);

            // Left or right screen border collision
            if (nextX < GameStateManagement.BORDER || nextX + this.SourceRectangle.Value.Width > GameStateManagement.DEFAULT_PORTRAIT_SCREEN_WIDTH - GameStateManagement.BORDER)
                this.Speed = new Vector2(0, this.Speed.Y);

            // Top or bottom screen border collision
            if (nextY <= GameStateManagement.BORDER + this.lifeBar.Position.Y + this.lifeBar.SourceRectangle.Value.Height || nextY + this.SourceRectangle.Value.Height >= GameStateManagement.DEFAULT_PORTRAIT_SCREEN_HEIGHT - GameStateManagement.BORDER)
                this.Speed = new Vector2(this.Speed.X, 0);

            base.Update(gameTime);

            #endregion

            #region Reactor Update

            this.reactor.Position = this.Position;
            this.reactor.Update(gameTime);

            #endregion
        }

        /// <summary>
        /// Draws the specified sprite batch.
        /// </summary>
        /// <param name="spriteBatch">The sprite batch.</param>
        public override void Draw(SpriteBatch spriteBatch)
        {
            this.reactor.Draw(spriteBatch);
            base.Draw(spriteBatch);
            this.lifeBar.Draw(spriteBatch, 100 * this.Life / this.InitialLife);
        }

        #endregion
    }
}
